﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using mesoBoard.Data.Repositories;
using mesoBoard.Data;

namespace mesoBoard.Services
{
    public class Forums : IForums
    {
         

        private IRepositoriesWrapper Repositories;

        public Forums(IRepositoriesWrapper repos)
        {
            this.Repositories = repos;
        }

        public void ChangeForumOrder(int forumID, int categoryID, int direction)
        {
            List<Forum> AllForums = GetForumsByCategory(categoryID).OrderBy(x => x.Order).ToList();
            Forum forum = AllForums.FirstOrDefault(x => x.ForumID == forumID);
            int IndexOfForum = AllForums.IndexOf(forum);
            forum.Order += direction;

            Forum displaced = null;

            switch (direction)
            {
                case 1:
                    displaced = AllForums.ElementAt(IndexOfForum + 1);
                    displaced.Order--;
                    
                    break;
                case -1:
                    displaced = AllForums.ElementAt(IndexOfForum - 1);
                    displaced.Order++;
                    break;
            }
            Repositories.Forums.UpdateForum(forum);
            Repositories.Forums.UpdateForum(displaced);
        }

        public void ChangeCategoryOrder(int categoryID, int direction)
        {
            List<Category> AllCats = Repositories.Categories.GetCategories().OrderBy(x => x.Order).ToList();
            Category TheCat = AllCats.FirstOrDefault(x => x.CategoryID == categoryID);
            int IndexOfCat = AllCats.IndexOf(TheCat);
            TheCat.Order += direction;

            Category displaced = null;

            switch (direction)
            {
                case 1:
                    displaced = AllCats.ElementAt(IndexOfCat + 1);
                    displaced.Order--;
                    break;
                case -1:
                    displaced = AllCats.ElementAt(IndexOfCat - 1);
                    displaced.Order++;
                    break;
            }

            Repositories.Categories.UpdateCategory(TheCat);
            Repositories.Categories.UpdateCategory(displaced);
        }

        public IEnumerable<Forum> GetForumsByCategory(int categoryID)
        {
            return Repositories.Forums.GetForums().Where(x => x.CategoryID == categoryID);
        }

        public IEnumerable<Forum> GetViewableForums(int userID)
        {
            IEnumerable<Forum> forums = Repositories.Forums.GetForums();

            IEnumerable<Forum> filtered = forums.Where(x => CanView(x.ForumID, userID));

            return filtered;
        }

        public IEnumerable<Category> GetViewableCategories(int userID)
        {
            IEnumerable<Forum> viewableForums = GetViewableForums(userID);

            return viewableForums.Select(x => x.Category).Distinct();
        }

        public int GetPermissionValue(int forumID, int userID, string Action)
        {
            Forum TheForum = Repositories.Forums.GetForum(forumID);

            IEnumerable<ForumPermission> Perms = Repositories.Permissions.GetForumPermissions(forumID);

            if (userID == 0)
            {
                ForumPermission tPerm = Perms.FirstOrDefault(x => x.Role.Name == "Guest");
                if (tPerm != null)
                {
                    switch (Action)
                    {
                        case "Posting":
                            return tPerm.Posting;
                        case "Polling":
                            return tPerm.Polling;
                        case "Visiblity":
                            return tPerm.Visibility;
                    }
                }
                else
                {
                    return 0;
                }
            }
            else
            {
                User TheUser = Repositories.Users.GetUser(userID);
                int Posting = 0;
                int Polling = 0;
                int Attachment = 0;
                foreach (InRole r in TheUser.InRoles)
                {
                    if (r.Role.Name == "Admin") return 10;
                    else if (r.Role.Name == "Moderator") return 5;
                    ForumPermission tPerm = Perms.FirstOrDefault(x => x.RoleID == r.RoleID);
                    if (tPerm != null)
                    {

                        switch (Action)
                        {
                            case "Posting":
                                Posting = Posting > tPerm.Posting ? Posting : tPerm.Posting;
                                break;
                            case "Polling":
                                Polling = Polling > tPerm.Polling ? Polling : tPerm.Polling;
                                break;
                            case "Attachment":
                                Attachment = Attachment > tPerm.Attachments ? Attachment : tPerm.Attachments;
                                break;
                            case "Visiblity":
                                return tPerm.Visibility;
                        }
                    }
                }
                if (Action == "Posting")
                    return Posting;
                else if (Action == "Polling")
                    return Polling;
                else if (Action == "Attachment")
                    return Attachment;
            }
            return 0;
        }

        private bool HasPermissionFor(int forumID, int userID, string Action)
        {
            IEnumerable<ForumPermission> Perms = Repositories.Permissions.GetForumPermissions(forumID);
            if (userID == 0)
            {
                ForumPermission tPerm = Perms.FirstOrDefault(x => x.Role.Name == "Guest");
                if (tPerm != null)
                {
                    switch (Action)
                    {
                        case "View": if (tPerm.Visibility > 0) return true;
                            break;
                        default: return false;
                            break;
                    }
                     
                }
                else
                    return false;
            }
            else
            {
                User TheUser = Repositories.Users.GetUser(userID);
                foreach (InRole r in TheUser.InRoles)
                {
                    if (r.Role.Name == "Admin") return true;
                    else if (r.Role.Name == "Moderator") return true;
                    ForumPermission tPerm = Perms.FirstOrDefault(x => x.RoleID == r.RoleID);
                    if (tPerm != null)
                    {
                        switch (Action)
                        {
                            case "View": if (tPerm.Visibility > 0) return true;
                                break;
                            case "Reply": if (tPerm.Posting >= 1) return true;
                                break;
                            case "CreateThread": if (tPerm.Posting >= 2) return true;
                                break;
                            case "CastVote": if (tPerm.Polling > 0) return true;
                                break;
                            case "CreatePoll": if (tPerm.Polling > 1) return true;
                                break;
                            case "DownloadAttachment": if (tPerm.Attachments > 0) return true;
                                break;
                            case "CreateAttachment": if (tPerm.Attachments > 1) return true;
                                break;
                        }
                    }
                }
            }

            return false;
        }

        public bool CanView(int forumID, int userID)
        {
            return HasPermissionFor(forumID, userID, "View");
        }

        public bool CanReply(int forumID, int userID)
        {
            return HasPermissionFor(forumID, userID, "Reply");
        }

        public bool CanCreateThread(int forumID, int userID)
        {
            return HasPermissionFor(forumID, userID, "CreateThread");
        }

        public bool CanCreatePoll(int forumID, int userID)
        {
            return HasPermissionFor(forumID, userID, "CreatePoll");
        }

        public bool CanCastVote(int forumID, int userID)
        {
            return HasPermissionFor(forumID, userID, "CastVote");
        }

        public bool CanCreateAttachment(int forumID, int userID)
        {
            return HasPermissionFor(forumID, userID, "CreateAttachment");
        }

        public bool CanDownloadAttachment(int forumID, int userID)
        {
            return HasPermissionFor(forumID, userID, "DownloadAttachment");
        }

        public bool CanLock(int forumID, int userID)
        {
            if (userID == 0)
                return false;

            IEnumerable<Role> userRoles = Repositories.Roles.GetRoles(userID);

            return userRoles.Any(x=>x.Name.Equals("Moderator") || x.Name.Equals("Admin"));
        }

        public bool HasNewPost(int forumID, int userID)
        {
            if (userID == 0)
                return false;

            Threads threads = new Threads(this.Repositories);

            IEnumerable<Thread> allThreads = Repositories.Threads.GetThreads(forumID);

            return allThreads.Any(x => threads.HasNewPost(x.ThreadID, userID));
        }

    }
}
